﻿#include <Sys\RenderUnit\SysRenderDatagram\LIGHTSOURCERD.HPP>

using namespace CxxlMan;
using namespace Cxxl3D;


/***********************************************************/
#define CLightAmbient_ClassID L"D9BBF991454A4fee9E7F0E53A6594C9F"

cxxlObject *cxxlFASTCALL New_CLightAmbient();
cxxlPreserve2 *cxxlFASTCALL Regenera_CLightAmbient(const wchar_t *ClassID);

class CLightAmbient:public ILightAmbient
{
  struct tagAmbient
  {
    C3D_FLOAT r,g,b,a;
  }m_Ambient;

  virtual void cxxlFASTCALL SysInit(const C3DVector4 &Ambient)
  {
    m_Ambient = (tagAmbient &)Ambient;
  }

  // 取得以下資料
  // Ambient = 附增環境顏色值 rgba
  virtual void cxxlFASTCALL GetData(C3DVector4 &Ambient)
  {
    (tagAmbient &)Ambient = m_Ambient;
  }

protected:
  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && ILightAmbient::Ref(F))
    {
      if(F->Ref((C3D_FLOAT *)&m_Ambient,4,L"AMB") == false) 
        return false;

      return true;
    }
    else
      return false;
  }

public:
  // Constructor
  CLightAmbient()
    :cxxlObject(CxxlMan::Spirit_Easy),
    CxxlMan::cxxlPreserve2(CLightAmbient_ClassID) // 在建構時指定 ClassID
  {}

  // Destructor
  virtual ~CLightAmbient(){}

  friend cxxlObject *cxxlFASTCALL New_CLightAmbient();
  friend cxxlPreserve2 *cxxlFASTCALL Regenera_CLightAmbient(const wchar_t *ClassID);
};

cxxlObject *cxxlFASTCALL New_CLightAmbient()
{
  return new CLightAmbient;
}

cxxlPreserve2 *cxxlFASTCALL Regenera_CLightAmbient(const wchar_t *ClassID)
{
  if(wcscmp(CLightAmbient_ClassID, ClassID) == 0)
    return new CLightAmbient;
  else
    return NULL;
}


/***********************************************************/

#define CLightDirectional_ClassID L"B743757054B646518009EC37F9189596"

cxxlObject *cxxlFASTCALL New_CLightDirectional();
cxxlPreserve2 *cxxlFASTCALL Regenera_CLightDirectional(const wchar_t *ClassID);

class CLightDirectional:public ILightDirectional
{
  struct tagSpecular
  {
    C3D_FLOAT r,g,b,a;
  }m_Specular;

  struct tagAmbient
  {
    C3D_FLOAT r,g,b,a;
  }m_Ambient;

  struct tagColor
  {
    C3D_FLOAT r,g,b,a;
  }m_Color;

  struct tagDirectional
  {
    C3D_FLOAT x,y,z;
  }m_Directional;


  virtual void cxxlFASTCALL SysInit(const C3DVector4 &Specular, const C3DVector4 &Ambient, const C3DVector4 &Color, const C3DVector4 &Directional)
  {
    m_Specular = (tagSpecular &)Specular;
    m_Ambient = (tagAmbient &)Ambient;
    m_Color = (tagColor &)Color;
    m_Directional = (tagDirectional &)Directional;
  }

  // 取得以下資料
  // Specular = 反射光的顏色值 rgba
  // Ambient = 附增環境顏色值 rgba
  // Color = 光線顏色值 rgba
  // Directional = 射出方向
  virtual void cxxlFASTCALL GetData(C3DVector4 &Specular, C3DVector4 &Ambient, C3DVector4 &Color, C3DVector4 &Directional)
  {
    (tagSpecular &)Specular = m_Specular;
    (tagAmbient &)Ambient = m_Ambient;
    (tagColor &)Color = m_Color;
    Directional.x = m_Directional.x;
    Directional.y = m_Directional.y;
    Directional.z = m_Directional.z;
    Directional.w = 0;
  }

  virtual void cxxlFASTCALL Accept(ILightSourceVisitor &visitor)
  {
    visitor.VisitLightDirectional(this);
  }


protected:

  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && ILightDirectional::Ref(F))
    {
      if(F->Ref((C3D_FLOAT *)&m_Specular,4,L"LD.SPE") == false) 
        return false;

      if(F->Ref((C3D_FLOAT *)&m_Ambient,4,L"LD.AMB") == false) 
        return false;

      if(F->Ref((C3D_FLOAT *)&m_Color,4,L"LD.CLR") == false) 
        return false;

      if(F->Ref((C3D_FLOAT *)&m_Directional,3,L"LD.DIR") == false) 
        return false;

      return true;
    }
    else
      return false;
  }

public:
  // Constructor
  CLightDirectional()
    :cxxlObject(CxxlMan::Spirit_Easy),
    CxxlMan::cxxlPreserve2(CLightDirectional_ClassID) // 在建構時指定 ClassID
  {}
  // Destructor
  virtual ~CLightDirectional(){}

  friend cxxlObject *cxxlFASTCALL New_CLightDirectional();
  friend cxxlPreserve2 *cxxlFASTCALL Regenera_CLightDirectional(const wchar_t *ClassID);

};

cxxlObject *cxxlFASTCALL New_CLightDirectional()
{
  return new CLightDirectional;
}

cxxlPreserve2 *cxxlFASTCALL Regenera_CLightDirectional(const wchar_t *ClassID)
{
  if(wcscmp(CLightDirectional_ClassID, ClassID) == 0)
    return new CLightDirectional;
  else
    return NULL;
}


/***********************************************************/

#define CLightPoint_ClassID L"D32718A1E8574ce9BB16ADC6E7488172"

cxxlObject *cxxlFASTCALL New_CLightPoint();
cxxlPreserve2 *cxxlFASTCALL Regenera_CLightPoint(const wchar_t *ClassID);


class CLightPoint:public ILightPoint
{
  struct tagSpecular
  {
    C3D_FLOAT r,g,b,a;
  }m_Specular;

  struct tagAmbient
  {
    C3D_FLOAT r,g,b,a;
  }m_Ambient;

  struct tagColor
  {
    C3D_FLOAT r,g,b,a;
  }m_Color;

  struct tagPosition
  {
    C3D_FLOAT x,y,z;
  }m_Position;

  struct tagAttenuation
  {
    C3D_FLOAT CONSTANT, LINEAR, QUADRATIC;
  }m_Attenuation;

  virtual void cxxlFASTCALL SysInit(const C3DVector4 &Specular, const C3DVector4 &Ambient, const C3DVector4 &Color, const C3DVector4 &Position, const C3DVector4 &Attenuation)
  {
    m_Specular = (tagSpecular &)Specular;
    m_Ambient = (tagAmbient &)Ambient;
    m_Color = (tagColor &)Color;
    m_Position = (tagPosition &)Position;

    m_Attenuation.CONSTANT = Attenuation.x;
    m_Attenuation.LINEAR = Attenuation.y;
    m_Attenuation.QUADRATIC = Attenuation.z;
  }

  // 取得以下資料
  // Specular = 反射光的顏色值 rgba
  // Ambient = 附增環境顏色值 rgba
  // Color = 光線顏色值 rgba
  // Directional = 射出方向
  virtual void cxxlFASTCALL GetData(C3DVector4 &Specular, C3DVector4 &Ambient, C3DVector4 &Color, C3DVector4 &Position, C3DVector4 &Attenuation)
  {
    (tagSpecular &)Specular = m_Specular;
    (tagAmbient &)Ambient = m_Ambient;
    (tagColor &)Color = m_Color;
    (tagPosition &)Position = m_Position;
    Position.w = 1;

    Attenuation.x = m_Attenuation.CONSTANT;
    Attenuation.y = m_Attenuation.LINEAR;
    Attenuation.z = m_Attenuation.QUADRATIC;
  }

  virtual void cxxlFASTCALL Accept(ILightSourceVisitor &visitor)
  {
    visitor.VisitLightPoint(this);
  }

protected:

  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && ILightPoint::Ref(F))
    {
      if(F->Ref((C3D_FLOAT *)&m_Specular,4,L"LD.SPE") == false) 
        return false;

      if(F->Ref((C3D_FLOAT *)&m_Ambient,4,L"LP.AMB") == false) 
        return false;

      if(F->Ref((C3D_FLOAT *)&m_Color,4,L"LP.CLR") == false) 
        return false;

      if(F->Ref((C3D_FLOAT *)&m_Position,4,L"LP.POS") == false) 
        return false;

      if(F->Ref((C3D_FLOAT *)&m_Attenuation,3,L"LP.ATT") == false) 
        return false;

      return true;
    }
    else
      return false;
  }


public:
  // Constructor
  CLightPoint()
    :cxxlObject(CxxlMan::Spirit_Easy),
    CxxlMan::cxxlPreserve2(CLightPoint_ClassID) // 在建構時指定 ClassID
  {}
  // Destructor
  virtual ~CLightPoint(){}

  friend cxxlObject *cxxlFASTCALL New_CLightPoint();
  friend cxxlPreserve2 *cxxlFASTCALL Regenera_CLightPoint(const wchar_t *ClassID);
};

cxxlObject *cxxlFASTCALL New_CLightPoint()
{
  return new CLightPoint;
}

cxxlPreserve2 *cxxlFASTCALL Regenera_CLightPoint(const wchar_t *ClassID)
{
  if(wcscmp(CLightPoint_ClassID, ClassID) == 0)
    return new CLightPoint;
  else
    return NULL;
}


/***********************************************************/

#define CLightSpot_ClassID L"B7638DC7084D4772ACE11E49AD6E8524"

cxxlObject *cxxlFASTCALL New_CLightSpot();
cxxlPreserve2 *cxxlFASTCALL Regenera_CLightSpot(const wchar_t *ClassID);


class CLightSpot:public ILightSpot
{
  struct tagSpecular
  {
    C3D_FLOAT r,g,b,a;
  }m_Specular;

  struct tagAmbient
  {
    C3D_FLOAT r,g,b,a;
  }m_Ambient;

  struct tagColor
  {
    C3D_FLOAT r,g,b,a;
  }m_Color;

  struct tagDirectional
  {
    C3D_FLOAT x,y,z;
  }m_Directional;

  struct tagPosition
  {
    C3D_FLOAT x,y,z;
  }m_Position;

  struct tagAttenuation
  {
    C3D_FLOAT CONSTANT, LINEAR, QUADRATIC;
  }m_Attenuation;
  
  C3D_FLOAT m_SpotlightCutoff, m_SpotlightExponent;

  virtual void cxxlFASTCALL SysInit(const C3DVector4 &Specular, const C3DVector4 &Ambient, const C3DVector4 &Color, const C3DVector4 &Directional, const C3DVector4 &Position, const C3DVector4 &Attenuation,
    C3D_FLOAT SpotlightCutoff, C3D_FLOAT SpotlightExponent)
  {
    m_Specular = (tagSpecular &)Specular;
    m_Ambient = (tagAmbient &)Ambient;
    m_Color = (tagColor &)Color;
    m_Directional = (tagDirectional &)Directional;
    m_Position = (tagPosition &)Position;

    m_Attenuation.CONSTANT = Attenuation.x;
    m_Attenuation.LINEAR = Attenuation.y;
    m_Attenuation.QUADRATIC = Attenuation.z;

    m_SpotlightCutoff = SpotlightCutoff;
    m_SpotlightExponent = SpotlightExponent;
  }

  // 取得以下資料
  // Specular = 反射光的顏色值 rgba
  // Ambient = 附增環境顏色值 rgba
  // Color = 光線顏色值 rgba
  // Directional = 射出方向
  // Position = 點光源的位置
  // Attenuation = 隨距離的衰減值，公式 1/(CONSTANT + LINEAR*d + QUADRATIC*d^2) 其中 d 為距離
  //               Attenuation 的前 3 個欄位值為公式中的 CONSTANT、LINEAR、QUADRATIC 值
  // SpotlightCutoff = 光柱圓錐一半的角度
  // SpotlightExponent = 光柱圓錐的角度衰減
  virtual void cxxlFASTCALL GetData(C3DVector4 &Specular, C3DVector4 &Ambient, C3DVector4 &Color, C3DVector4 &Directional, C3DVector4 &Position, C3DVector4 &Attenuation, 
    C3D_FLOAT &SpotlightCutoff, C3D_FLOAT &SpotlightExponent)
  {
    (tagSpecular &)Specular = m_Specular;
    (tagAmbient &)Ambient = m_Ambient;
    (tagColor &)Color = m_Color;
    (tagDirectional &)Directional = m_Directional;
    Directional.w = 0;
    (tagPosition &)Position = m_Position;
    Position.w = 1;

    Attenuation.x = m_Attenuation.CONSTANT;
    Attenuation.y = m_Attenuation.LINEAR;
    Attenuation.z = m_Attenuation.QUADRATIC;

    SpotlightCutoff = m_SpotlightCutoff;
    SpotlightExponent = m_SpotlightExponent;
  }

  virtual void cxxlFASTCALL Accept(ILightSourceVisitor &visitor)
  {
    visitor.VisitLightSpot(this);
  }

protected:

  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && ILightSpot::Ref(F))
    {
      if(F->Ref((C3D_FLOAT *)&m_Specular,4,L"LD.SPE") == false) 
        return false;

      if(F->Ref((C3D_FLOAT *)&m_Ambient,4,L"LS.AMB") == false) 
        return false;

      if(F->Ref((C3D_FLOAT *)&m_Color,4,L"LS.CLR") == false) 
        return false;

      if(F->Ref((C3D_FLOAT *)&m_Directional,4,L"LS.DIR") == false) 
        return false;

      if(F->Ref((C3D_FLOAT *)&m_Position,4,L"LS.POS") == false) 
        return false;

      if(F->Ref((C3D_FLOAT *)&m_Attenuation,3,L"LS.ATT") == false) 
        return false;

      if(F->Ref(&m_SpotlightCutoff, 1, L"LS.SC") == false) 
        return false;

      if(F->Ref(&m_SpotlightExponent, 1, L"LS.SE") == false) 
        return false;

      return true;
    }
    else
      return false;
  }


public:
  // Constructor
  CLightSpot()
    :cxxlObject(CxxlMan::Spirit_Easy),
    cxxlPreserve2(CLightSpot_ClassID) // 在建構時指定 ClassID
  {}
  // Destructor
  virtual ~CLightSpot(){}

  friend cxxlObject *cxxlFASTCALL New_CLightSpot();
  friend cxxlPreserve2 *cxxlFASTCALL Regenera_CLightSpot(const wchar_t *ClassID);

};


cxxlObject *cxxlFASTCALL New_CLightSpot()
{
  return new CLightSpot;
}

cxxlPreserve2 *cxxlFASTCALL Regenera_CLightSpot(const wchar_t *ClassID)
{
  if(wcscmp(CLightSpot_ClassID, ClassID) == 0)
    return new CLightSpot;
  else
    return NULL;
}


/***********************************************************/

#define CLightSourceMgr_ClassID L"1A2CEAC6C45146a59BF905D9AB5F5559"

cxxlObject *cxxlFASTCALL New_CLightSourceMgrRD();
cxxlPreserve2 *cxxlFASTCALL Regenera_CLightSourceMgrRD(const wchar_t *ClassID);


class CLightSourceMgrRD:public ILightSourceMgrRD
{
  bool m_isModified;

  P2Smart_Ptr<ILightAmbient> m_ILightAmbient_Ptr;

  P2Smart_Set<ILightSource> m_ILightSource_Set;

  // 設定環境光
  virtual void cxxlFASTCALL SetAmbient(const Smart_Ptr<ILightAmbient> &Ambient)
  {
    csPreserve.Enter();
    m_ILightAmbient_Ptr = Ambient;
    m_isModified = true;
    csPreserve.Leave();
  }

  // 取得環境光 
  virtual void cxxlFASTCALL GetAmbient(Smart_Ptr<ILightAmbient> &Ambient)
  {
    csPreserve.Enter();
    Ambient = m_ILightAmbient_Ptr;
    csPreserve.Leave();
  }

  // 最多只能放進 8 個，若滿了回覆 false
  virtual bool cxxlFASTCALL Bind(const CxxlMan::Smart_Ptr<ILightSource> &ILightSource_Arg)
  {
    CriticalSecHandle AutoCSH(csPreserve);
    if(m_ILightSource_Set.GetCount() == 8)
      return false;

    m_ILightSource_Set.Add(ILightSource_Arg);
    m_isModified = true;
    return true;
  }

  // 剔除指定的光源
  virtual void cxxlFASTCALL UnBind(const CxxlMan::Smart_Ptr<ILightSource> &ILightSource_Arg)
  {
    csPreserve.Enter();
    m_ILightSource_Set.Delete(ILightSource_Arg);
    m_isModified = true;
    csPreserve.Leave();
  }

  // 取得所有光源
  virtual CxxlMan::Smart_Ptr<CxxlMan::cxxlList<ILightSource> > GetILightSources()
  {
    CriticalSecHandle AutoCSH(csPreserve);

    return m_ILightSource_Set.GetList();    
  }

  // 由 Render 單元叫用，並恢復設定為 false
  virtual bool cxxlFASTCALL isModified()
  {
    CriticalSecHandle AutoCSH(csPreserve);

    bool vIsModified = m_isModified;
    m_isModified = false;

    return vIsModified;
  }


protected:

  // 儲存容器藉此取得要永續存取的屬性資料
  // 延伸類別須以 virtual 的形式覆寫
  // 並且須呼叫上層類別的此函數
  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && ILightSourceMgrRD::Ref(F))
    {
      LoadFilter *pLoadFilter = dynamic_cast<LoadFilter*>(F);
      if(pLoadFilter && pLoadFilter->isChk() == false)      
        m_isModified = true;

      return true;
    }
    else
      return false;
  }


public:
  // Constructor
  CLightSourceMgrRD()
    :cxxlObject(CxxlMan::Spirit_Easy),
    cxxlPreserve2(CLightSourceMgr_ClassID), // 在建構時指定 ClassID
    m_ILightAmbient_Ptr(NULL,this,L"LMgr.AMB"),
    m_ILightSource_Set(this,L"LMgr.LSet")
  {
    m_isModified = true;
  }

  // Destructor
  ~CLightSourceMgrRD(){}

  friend cxxlObject *cxxlFASTCALL New_CLightSourceMgrRD();
  friend cxxlPreserve2 *cxxlFASTCALL Regenera_CLightSourceMgrRD(const wchar_t *ClassID);
};

cxxlObject *cxxlFASTCALL New_CLightSourceMgrRD()
{
  return new CLightSourceMgrRD;
}

cxxlPreserve2 *cxxlFASTCALL Regenera_CLightSourceMgrRD(const wchar_t *ClassID)
{
  if(wcscmp(CLightSourceMgr_ClassID, ClassID) == 0)
    return new CLightSourceMgrRD;
  else
    return NULL;
}
